package proxy

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/elazarl/goproxy"
)

var (
	certPath = "cert"
	certFile = filepath.Join(certPath, "cert.pem")
	keyFile  = filepath.Join(certPath, "privateKey.pem")
)

func Run() {
	// 创建证书目录
	if err := os.MkdirAll(certPath, 0755); err != nil {
		log.Fatal("创建证书目录失败:", err)
	}

	// 保存内置证书
	if err := saveBuiltinCert(); err != nil {
		log.Fatal("保存证书失败:", err)
	}

	proxy := goproxy.NewProxyHttpServer()
	proxy.Verbose = false

	// 设置日志输出
	logFile, err := os.Create("proxy.log")
	if err != nil {
		log.Fatal("无法创建日志文件:", err)
	}
	defer logFile.Close()

	logger := log.New(logFile, "", log.LstdFlags)
	proxy.Logger = logger

	// 打印所有请求的完整URL
	proxy.OnRequest().DoFunc(
		func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			reqUrl := getFullURL(r)
			// 检查路径是否包含"motor"
			if strings.Contains(strings.ToLower(reqUrl.Path), "api/search/gas_station/oil_price_trend") {
				// fullURL := reqUrl.String()
				// log.Printf("请求: %s %s", r.Method, fullURL)
				// logger.Printf("请求: %s %s\nHeaders: %v", r.Method, fullURL, r.Header)

				ctx.UserData = "logResponse" // 标记需要记录响应
			}
			return r, nil
		})

	// 处理响应 - 只有当请求路径包含"motor"时才记录
	proxy.OnResponse().DoFunc(
		func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
			if ctx.UserData == "logResponse" {
				// 读取响应体
				body, err := io.ReadAll(resp.Body)
				if err != nil {
					log.Printf("读取响应体错误: %v", err)
					return resp
				}

				// 恢复响应体，不然会影响到代理客户端的响应结果
				resp.Body = io.NopCloser(bytes.NewReader(body))

				// 打印响应信息
				log.Printf("【%s】%s\n状态码: %d\n响应体: %s",
					ctx.Req.Method, getFullURL(ctx.Req).Path,
					resp.StatusCode, string(body))
				logger.Printf("响应: %s %s\n状态码: %d\nHeaders: %v\n响应体: %s",
					ctx.Req.Method, getFullURL(ctx.Req).Path,
					resp.StatusCode, resp.Header, string(body))
			}
			return resp
		})

	// 处理HTTPS连接
	proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

	// 忽略证书错误（仅用于调试）
	proxy.Tr = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	go func() {
		mux1 := http.NewServeMux()
		// 设置文件下载路由
		mux1.HandleFunc("/cert", func(w http.ResponseWriter, r *http.Request) {
			// 设置要下载的文件路径
			filePath := "./cert/cert.pem"
			// 打开文件
			file, err := os.Open(filePath)
			if err != nil {
				http.Error(w, "文件未找到", http.StatusNotFound)
				return
			}
			defer file.Close()

			// 获取文件信息
			fileInfo, err := file.Stat()
			if err != nil {
				http.Error(w, "无法获取文件信息", http.StatusInternalServerError)
				return
			}

			// 设置响应头，强制浏览器下载
			w.Header().Set("Content-Disposition", "attachment; filename=cert.pem")
			w.Header().Set("Content-Type", "application/x-x509-ca-cert")
			w.Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))

			// 支持断点续传
			http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), file)
		})

		log.Println("请访问 http://[本机IP]:9082/cert 下载证书")
		log.Fatal(http.ListenAndServe(":9082", mux1))
	}()

	log.Println("代理服务器启动在 :9081")
	log.Fatal(http.ListenAndServe(":9081", proxy))
}

// 保存内置证书
func saveBuiltinCert() error {
	// 检查证书是否已存在
	if _, err := os.Stat(certFile); err == nil {
		return nil
	}

	// 保存证书
	if err := os.WriteFile(certFile, goproxy.CA_CERT, 0644); err != nil {
		return fmt.Errorf("保存证书失败: %v", err)
	}
	if err := os.WriteFile(keyFile, goproxy.CA_KEY, 0600); err != nil {
		return fmt.Errorf("保存私钥失败: %v", err)
	}

	return nil
}

// getFullURL 构建完整的请求URL
func getFullURL(r *http.Request) *url.URL {
	u := &url.URL{
		Scheme:   r.URL.Scheme,
		Host:     r.Host,
		Path:     r.URL.Path,
		RawQuery: r.URL.RawQuery,
	}

	if u.Scheme == "" {
		if r.TLS != nil {
			u.Scheme = "https"
		} else {
			u.Scheme = "http"
		}
	}

	if u.Host == "" {
		u.Host = r.URL.Host
	}

	return u
}
